﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Autodesk.AutoCAD.Customization;
using Autodesk.AutoCAD.Runtime;

namespace AutoCADDotNetLibrary
{
    /// <summary>
    /// 宏特性
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class MenuMacroAttribute : Attribute
    {
        /// <summary>
        /// 宏特性
        /// </summary>
        /// <param name="name">名称</param>
        public MenuMacroAttribute(string name)
        {
            Name = name;
        }

        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// 元素Id（AutoCAD会自动生成）
        /// </summary>
        public string UID { get; set; }

        /// <summary>
        /// 类型
        /// </summary>
        public MacroType Type { get; set; }

        /// <summary>
        /// 说明
        /// </summary>
        public string HelpString { get; set; }

        /// <summary>
        /// 小图像（dll的相对路径bmp位图，读取的位图会自动复制压缩到cuix文件中）
        /// </summary>
        public string SmallImageFileName { get; set; }

        /// <summary>
        /// 大图像（dll的相对路径bmp位图，读取的位图会自动复制压缩到cuix文件中）
        /// </summary>
        public string LargeImageFileName { get; set; }

        /// <summary>
        /// 命令显示名
        /// </summary>
        public string CLICommand { get; set; }


        /// <summary>
        /// 特性转换
        /// </summary>
        /// <param name="menu">宏组</param>
        /// <param name="command">宏</param>
        /// <returns></returns>
        internal MenuMacro GetMenuMacro(MacroGroup menu, string command)
        {
            MenuMacro m = new MenuMacro(menu, Name, "^C^C" + command.Trim() + " ", UID, Type);
            m.macro.CLICommand = CLICommand;
            m.macro.HelpString = HelpString;

            if (!string.IsNullOrEmpty(SmallImageFileName))
            {
                if (File.Exists(SmallImageFileName))
                {
                    m.macro.SmallImage = SmallImageFileName;
                }
                else
                {
                    throw new System.Exception($"{nameof(MenuMacroAttribute)}的属性{nameof(SmallImageFileName)}:\"{SmallImageFileName}\"路径错误");
                }
            }
            if (!string.IsNullOrEmpty(LargeImageFileName))
            {
                if (File.Exists(LargeImageFileName))
                {
                    m.macro.LargeImage = LargeImageFileName;
                }
                else
                {
                    throw new System.Exception($"{nameof(MenuMacroAttribute)}的属性{nameof(LargeImageFileName)}:\"{LargeImageFileName}\"路径错误");
                }
            }

            return m;
        }
    }

    /// <summary>
    /// 宏特性
    /// </summary>
    public static class MenuMacroAtt
    {
        /// <summary>
        /// 根据调用函数的程序集的所有具有实现了<see cref="MenuMacroAttribute"/>和<see cref="CommandMethodAttribute"/>的函数，将这些函数添加到CUI命令列表中
        /// </summary>
        /// <param name="menu">宏</param>
        /// <param name="assembly">程序集，默认为调用的程序集</param>
        /// <returns>key=命令,value=宏</returns>
        public static Dictionary<string, MenuMacro> AddAssemblyMenuMacro(this MacroGroup menu, Assembly assembly)
        {
            string dir = Environment.CurrentDirectory;
            Environment.CurrentDirectory = Path.GetDirectoryName(assembly.Location);//设置dll的路径为相对路径，以便于设置SmallImageFileName和LargeImageFileName

            try
            {
                Dictionary<string, MenuMacro> list = assembly.GetTypes().SelectMany(x => x.GetMethods()).Select(x => new
                {
                    Command = x.GetCustomAttributes(typeof(CommandMethodAttribute), false).OfType<CommandMethodAttribute>(),
                    Macro = x.GetCustomAttributes(typeof(MenuMacroAttribute), false).OfType<MenuMacroAttribute>(),
                }).Where(x => x.Macro.Count() != 0 && x.Command.Count() != 0)
               .Select(x => new
               {
                   Command = x.Command.First().GlobalName,
                   Macro = x.Macro.First()
               }).OrderBy(x => x.Macro.Name).ToDictionary(x => x.Command, x =>
               {
                   return x.Macro.GetMenuMacro(menu, x.Command);
               });

                return list;
            }
            finally
            {
                Environment.CurrentDirectory = dir;
            }
        }
    }
}